""" 
Frame contains the mail frame which holds all of the relevant widgets
and functionality of the KuplaMail project.
Written By: Daniel Ortiz
"""
import wx
# GUI
from splitter import  MailSplitter
from printing import MailPrintout
from text import MailSearchText
from frames.add import AddFrame
from frames.address import AddressFrame
from frames.help import HelpFrame
import images.images as images
import wx.html
# Handlers
from handler.history import HistoryBuffer
from handler.mailbox import MailboxHandler
from handler.bundle import Bundle
from handler.dbhandler import DatabaseHandler
from handler.check import MailboxCheckHandler
from handler.mail import MailStateHandler
#Twisted
from twisted.internet import reactor

class MailFrame(wx.Frame):
    def __init__(self, broker):
        self.broker = broker
        wx.Frame.__init__(self, None, size = (1024, 768))
        self.Variables()
        self.InstantiateChildren()
        self.CreateMenu()
        self.CreateToolbar()
        self.CreateStatusbar()
        self.BindEvents()
        self.CenterOnScreen()
        
    def Variables(self):
        """Class wide variables are initialized here"""
        self.resize = False
        self.dtime = 5
        self.original_size = (800, 600)
        self.InitializeHandlers()
        self.InitializePrintData()
        self.address_frame = None
        
    def InitializeHandlers(self):
        """Initialize the handlers which bridget the gap between the gui/memory and 
        the gui/network"""
        self.history_buffer = HistoryBuffer()
        self.mail_text_bundle = Bundle(wx.TextCtrl, self)
        self.database_handler = DatabaseHandler(self, self.broker)
        self.mailbox_check_handler = MailboxCheckHandler(self)
        self.mailbox_check_handler.BindDatabaseHandler(self.database_handler)
        self.mail_state_handler = MailStateHandler(self)
        self.mail_state_handler.BindDatabaseHandler(self.database_handler)
        self.printer_handler = wx.html.HtmlEasyPrinting("Printing", self)

    def InitializePrintData(self):
        """Function initializes the print data"""
        self.pdata = wx.PrintData()
        self.pdata.SetPaperId(wx.PAPER_LETTER)
        self.pdata.SetOrientation(wx.PORTRAIT)
        self.margins = (wx.Point(15, 15), wx.Point(15, 15))
        
    def InstantiateChildren(self):
        """Creates all of the children widgets"""
        self.splitter_window = MailSplitter(self)
        
    def CreateMenu(self):
        """Function creates the menu for the frame"""
        file_menu = wx.Menu()
        page_setup = file_menu.Append(-1, "Page Setup\tCtrl-Shift-p")
        pri = file_menu.Append(-1, "Print\tCtrl-p")
        #pripreview = file_menu.Append(-1, "Print Preview\tCtrl-Alt-p")
        file_menu.AppendSeparator()
        quit = file_menu.Append(-1, "Quit\tCtrl-q")
        self.Bind(wx.EVT_MENU, self.OnPageSetup, page_setup)
        self.Bind(wx.EVT_MENU, self.OnPrint, pri)
        #self.Bind(wx.EVT_MENU, self.OnPrintPreview, pripreview)
        self.Bind(wx.EVT_MENU, self.OnQuit, quit)
        edit_menu = wx.Menu()
        undo = edit_menu.Append(wx.ID_UNDO, "Undo\tCtrl-z")
        redo = edit_menu.Append(wx.ID_REDO, "Redo\tCtrl-y")
        edit_menu.AppendSeparator()
        cut = edit_menu.Append(wx.ID_CUT, "Cut\tCtrl-x")
        copy = edit_menu.Append(wx.ID_COPY, "Copy\tCtrl-c")
        paste = edit_menu.Append(wx.ID_PASTE, "Paste\tCtrl-v")
        edit_menu.AppendSeparator()
        select_all = edit_menu.Append(wx.ID_SELECTALL, "Select All\tCtrl-a")
        self.idedit = {"Undo" : undo.GetId(), "Redo" : redo.GetId(), "Cut" : cut.GetId(), 
                       "Copy" : copy.GetId(), "Paste" : paste.GetId(), "SelectAll" : select_all.GetId()}
        
        #find = edit_menu.Append(wx.ID_FIND, "Find\tCtrl-f")
        #replace = edit_menu.Append(-1, "Replace\tCtrl-Shift-r")
        self.Bind(wx.EVT_MENU, self.OnUndo, undo)
        self.Bind(wx.EVT_MENU, self.OnRedo, redo)
        self.Bind(wx.EVT_MENU, self.OnCut, cut)
        self.Bind(wx.EVT_MENU, self.OnCopy, copy)
        self.Bind(wx.EVT_MENU, self.OnPaste, paste)
        self.Bind(wx.EVT_MENU, self.OnSelectAll, select_all)
        #self.Bind(wx.EVT_MENU, self.OnFind, find)
        #self.Bind(wx.EVT_MENU, self.OnReplace, replace)
        mailbox_menu = wx.Menu()
        synch = mailbox_menu.Append(-1, "Synchronize\tCtrl-e")
        new_mailbox = mailbox_menu.Append(-1, "New Mailbox\tCtrl-n")
        new_folder = mailbox_menu.Append(-1, "New Folder\tCtrl-f")
        #hide_mailbox = mailbox_menu.Append(-1, "Hide Mailbox")
        address_book = mailbox_menu.Append(-1, "Address Book\tCtrl-k")
        self.Bind(wx.EVT_MENU, self.OnSynch, synch)
        self.Bind(wx.EVT_MENU, self.OnNewMailbox, new_mailbox)
        self.Bind(wx.EVT_MENU, self.OnNewFolder, new_folder)
        #self.Bind(wx.EVT_MENU, self.OnHideMailbox, hide_mailbox)
        self.Bind(wx.EVT_MENU, self.OnAddressBook, address_book)
        mail_menu = wx.Menu()
        attach = mail_menu.Append(-1, "Attach...")
        save_attach = mail_menu.Append(-1, "Save Attachments")
        mail_menu.AppendSeparator()
        reply = mail_menu.Append(-1, "Reply\tCtrl-r")
        reply_all = mail_menu.Append(-1, "Reply All\tCtrl-Shift-a")
        compose = mail_menu.Append(-1, "Compose\tCtrl-Shift-c")
        forward = mail_menu.Append(-1, "Forward\tCtrl-alt-f")
        send = mail_menu.Append(-1, "Send\tCtrl-s")
        self.Bind(wx.EVT_MENU, self.OnReply, reply)
        self.Bind(wx.EVT_MENU, self.OnReplyAll, reply_all)
        self.Bind(wx.EVT_MENU, self.OnCompose, compose)
        self.Bind(wx.EVT_MENU, self.OnForward, forward)
        self.Bind(wx.EVT_MENU, self.OnSend, send)
        self.Bind(wx.EVT_MENU, self.OnAttach, attach)
        self.Bind(wx.EVT_MENU, self.OnSaveAttach, save_attach)
        self.format_menu = wx.Menu()
        font = self.format_menu.Append(-1, "Font\tCtrl-Shift-f")
        color = self.format_menu.Append(-1, "Color\tCtrl-Alt-c")
        self.format_menu.AppendSeparator()
        bold = self.format_menu.Append(-1, "Bold\tCtrl-b")
        italic = self.format_menu.Append(-1, "Italic\tCtrl-i")
        underline = self.format_menu.Append(-1, "Underline\tCtrl-u")
        self.format_menu.AppendSeparator()
        align_left = self.format_menu.Append(-1, "Align Left\tCtrl-[")
        center = self.format_menu.Append(-1, "Center\tCtrl-|")
        align_right = self.format_menu.Append(-1, "Align Right\tCtrl-]")
        self.Bind(wx.EVT_MENU, self.OnFont, font)
        self.Bind(wx.EVT_MENU, self.OnColor, color)
        self.Bind(wx.EVT_MENU, self.OnBold, bold)
        self.Bind(wx.EVT_MENU, self.OnItalic, italic)
        self.Bind(wx.EVT_MENU, self.OnUnderline, underline)
        self.Bind(wx.EVT_MENU, self.OnAlignLeft, align_left)
        self.Bind(wx.EVT_MENU, self.OnCenter, center)
        self.Bind(wx.EVT_MENU, self.OnAlignRight, align_right)
        self.format_browser_menu = wx.Menu()
        home = self.format_browser_menu.Append(-1, "Home\tCtrl-h")
        forward = self.format_browser_menu.Append(-1, "Forward\tCtrl-shift-f")
        back = self.format_browser_menu.Append(-1, "Back\tCtrl-shift-b")
        self.format_browser_menu.AppendSeparator()
        increase = self.format_browser_menu.Append(-1, "Increase\tCtrl-+")
        decrease = self.format_browser_menu.Append(-1, "Decrease\tCtrl--")
        self.Bind(wx.EVT_MENU, self.OnHome, home)
        self.Bind(wx.EVT_MENU, self.OnBack, back)
        self.Bind(wx.EVT_MENU, self.OnForwardPage, forward)
        self.Bind(wx.EVT_MENU, self.OnIncrease, increase)
        self.Bind(wx.EVT_MENU, self.OnDecrease, decrease)
        help_menu = wx.Menu()
        help = help_menu.Append(-1, "KuplaMail Help\tCtrl-h")
        self.Bind(wx.EVT_MENU, self.OnHelp, help)
        menubar = wx.MenuBar()
        menubar.Append(file_menu, 'File')
        menubar.Append(edit_menu, "Edit")
        menubar.Append(mailbox_menu, "Mailbox")
        menubar.Append(mail_menu, "Mail")
        menubar.Append(self.format_browser_menu, "Format")
        menubar.Append(help_menu, "Help")
        for edit, id in self.idedit.iteritems():
            menubar.Enable(id, False)
        self.SetMenuBar(menubar)
        
    def CreateStatusbar(self):
        """Create the status bar for the frame"""
        #self.feedback = self.CreateStatusBar()
        pass
    
    def ChangeFormatMenu(self, is_text):
        """Change the format menu for the current browser"""
        mb = self.GetMenuBar()
        m = mb.GetMenu(4)
        if not is_text:
            if m != self.format_browser_menu:
                mb.Replace(4, self.format_browser_menu, "Format")
        else:
            if m != self.format_menu:
                mb.Replace(4, self.format_menu, "Format")
            
    def CreateToolbar(self):
        """Function creates the frames toolbar"""
        toolbar = self.CreateToolBar()
        bitmap_size = (64, 64)
        toolbar.SetToolBitmapSize(bitmap_size)
        empty_bitmap = images.getEmptyBitmap()
        self.search_window = MailSearchText(toolbar)
        toolbar.AddTool(-1, empty_bitmap)
        toolbar.AddTool(-1, empty_bitmap)
        toolbar.AddSeparator()
        new = toolbar.AddTool(-1, images.getNewBitmap(),
                            shortHelpString="New")
        compose = toolbar.AddTool(-1, images.getComposeBitmap(),
                                  shortHelpString = "Compose")
        send = toolbar.AddTool(-1, images.getSendBitmap(),
                               shortHelpString = "Send")
        reply = toolbar.AddTool(-1, images.getReplyBitmap(),
                                shortHelpString = "Reply")
        replyall = toolbar.AddTool(-1, images.getReplyAllBitmap(),
                                   shortHelpString = "Reply All")
        forward = toolbar.AddTool(-1, images.getForwardBitmap(),
                                  shortHelpString = "Forward")
        delete = toolbar.AddTool(-1, images.getDeleteBitmap(),
                                 shortHelpString="Delete")
        self.Bind(wx.EVT_TOOL, self.OnNewMailbox, new)
        self.Bind(wx.EVT_TOOL, self.OnCompose, compose)
        self.Bind(wx.EVT_TOOL, self.OnForward, forward)
        self.Bind(wx.EVT_TOOL, self.OnReply, reply)
        self.Bind(wx.EVT_TOOL, self.OnSend, send)
        self.Bind(wx.EVT_TOOL, self.OnReplyAll, replyall)
        self.Bind(wx.EVT_TOOL, self.OnDelete, delete)
        toolbar.AddSeparator()
        toolbar.AddTool(-1, empty_bitmap)
        toolbar.AddTool(-1, empty_bitmap)
        toolbar.AddControl(self.search_window)
        toolbar.Realize()
        
    def BindEvents(self):
        """Bind the relevant frame events"""
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_IDLE, self.OnIdle)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
#        self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
#        self.Bind(wx.EVT_FIND, self.FindValue)
#        self.Bind(wx.EVT_FIND_REPLACE, self.FindValue)
#        self.Bind(wx.EVT_FIND_REPLACE_ALL, self.FindValue)
#        self.Bind(wx.EVT_FIND_NEXT, self.FindValue)
        
    def OnSize(self, event):
        """Set the resize flag"""
        self.resize = True
        event.Skip()
        
    def OnIdle(self, event):
        """Resize events, and external processes are handled when the gui is idle"""
        if self.resize:
            self.resize = False
        self.database_handler.OnIdle()
    
    def OnClose(self, event):
        """Close the connection"""
        print 'inside'
        d = self.database_handler.OnQuit()
        d.addCallback(lambda _: self.FinalizeClose())
        d.addErrback(self.CloseWithError)

    def CloseWithError(self, d):
        print d
        self.FinalizeClose()
    
    def FinalizeClose(self):
        """Destroys the window and stops the reactor"""
        self.Destroy()
        try:
            reactor.stop()
        except Exception, e:
            print e
    
    # MENU/TOOLBAR EVENTS #
    def OnPageSetup(self, event):
        """Setup the page layout for the current page"""
        self.printer_handler.PageSetup()
    
    def OnPrint(self, event):
        """Print out the current document"""
        notebook = self.database_handler.notebook
        html_text = notebook.GetCurrentHTML()
        self.printer_handler.PrintText(html_text)
        
    def OnPrintPreview(self, event):
        """Create a print preview of the relevant html file"""
        notebook = self.database_handler.notebook
        html_text = notebook.GetCurrentHTML()
        self.printer_handler.PreviewFile(html_text)
        
    def OnQuit(self, event):
        """Quit the application"""
        self.Close()
    
    def OnUndo(self, event):
        event.Skip()
        
    def OnRedo(self, event):
        event.Skip()
    
    def OnCut(self, event):
        event.Skip()
    
    def OnCopy(self, event):
        event.Skip()
    
    def OnPaste(self, event):
        event.Skip()
    
    def OnSelectAll(self, event):
        event.Skip()
        
    def OnSynch(self, event):
        """Synchronize with the server"""
        self.database_handler.SynchServer()
    
    def OnHideMailbox(self, event):
        event.Skip()
        
    def OnAddressBook(self, event):
        if not self.address_frame:
            self.address_frame = AddressFrame(self, self.database_handler.broker, data = self.database_handler.book_address)
            self.address_frame.Show()
            
    def OnNewFolder(self, event):
        """Add a new folder to the folder tree"""
        if self.database_handler.HasMailbox():
            folder_tree = self.database_handler.GetFolderTree()
            folder_tree.NewFolder()
        else:
            wx.MessageBox("Please setup a mailbox (Ctrl-N) before adding a folder.", "Warning", wx.ID_OK)
    def OnNewMailbox(self, event):
        """Open the add frame for a new mailbox"""
        self.addframe = AddFrame(self, 'Add', self.mailbox_check_handler)
        self.addframe.Show()
        
    def OnHelp(self, event):
        """Open the help frame"""
        self.help_frame = HelpFrame(self)
        self.help_frame.Show()
        
    def OnCompose(self, event):
        """Compose a new mail"""
        self.mail_state_handler.OnCompose(event)
        
    def OnReply(self, event):
        """Reply to the current mail"""
        self.mail_state_handler.OnReply(event)
    
    def OnReplyAll(self, event):
        """Reply to the curren mail, and attach cc, and bcc"""
        self.mail_state_handler.OnReplyAll(event)
        
    def OnForward(self, event):
        """Forward the current mail"""
        self.mail_state_handler.OnForward(event)
        
    def OnSend(self, event):
        """Send the current mail"""
        self.mail_state_handler.OnSend(event)
        
    def OnAttach(self, event):
        """Attach a piece of mail in the current mail"""
        self.database_handler.NewAttachment()
    
    def OnSaveAttach(self, event):
        """Save all of the attachments of the current email"""
        self.database_handler.SaveAttachments()
        
    # Mail Browser Format Events
    def OnDecrease(self, event):
        """Decrease the text size of the mail browser""" 
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.DecreaseTextSize()
   
    def OnIncrease(self, event):
        """Increase the text size of the mail browser"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.IncreaseTextSize()
        
    def OnForwardPage(self, event):
        """Move forward to the next page in the browser"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.GoForward()
        
    def OnBack(self, event):   
        """Move backwards to the previous page in the browser"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.GoBack()
        
    def OnHome(self, event):
        """Move to the home in the WebKitCtrl"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.ReloadMail()
        
    # RTC Format events
    def OnFont(self, event):
        """Change the font in the richtextctrl"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.OnFont(event)
        
    def OnColor(self, event):
        """Change the color of the text in the richtextctrl"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.OnColor(event)
        
    def OnBold(self, event):
        """Set the current text to bold"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.OnBold(event)
        
    def OnItalic(self, event):
        """Set the current text to italic"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.OnItalic(event)
        
    def OnUnderline(self, event):
        """Set the current text to bold"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.OnUnderline(event)
        
    def OnAlignLeft(self, event):
        """Align the text to the left"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.OnAlignLeft(event)
        
    def OnCenter(self, event):
        """Align the text to the center"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.OnAlignCenter(event)
        
    def OnAlignRight(self, event):
        """Align the text to the right"""
        p = self.splitter_window.GetCurrentNotebookPage()
        p.mail_browser.OnAlignRight(event)
        
    def OnDelete(self, event):
        """Delete the value only within the mail list"""
        l = self.database_handler.mail_list
        l.DeleteSelection()
#    def OnFind(self, event):
#        """Find a string in the selection"""
#        self.first_query = True
#        self.previous_flags = -1
#        data = wx.FindReplaceData()
#        self.find_data_dialog = wx.FindReplaceDialog(self, data, "Find Word")
#        self.find_data_dialog.data = data
#        self.find_data_dialog.Show(True)
#        
#    def OnFindClose(self, event):
#        """This funtion closes the dialog box"""
#        event.GetDialog().Destroy()
#        
#    def OnReplace(self, event):
#        """Replace a string in the selection"""
#        self.first_query = True
#        self.previous_flags = -1
#        data = wx.FindReplaceData()
#        dlg = wx.FindReplaceDialog(self, data, "Find & Replace", wx.FR_REPLACEDIALOG)
#        dlg.data = data
#        dlg.Show(True)
#
#    def FindValue(self, event):
#        """Generic funcion for finding/replacing values in the RichTextCtrl"""
#        et = event.GetEventType()
#        self.find_string = event.GetFindString()
#        self.replace_string = event.GetReplaceString()
#        p = self.FindFocus()
#        self.flags = event.GetFlags()
#        if self.first_query:
#            self.search_index = self.mail_text_bundle.GetCurrentLocation()
#            self.search_buffer = self.mail_text_bundle.CurrentString()
#            self.first_query = False
#            if self.previous_flags == -1:
#                self.previous_flags = self.flags
#        self.GetFindFlags()
#        r = self.GetFindBuffer()
#        if not r:
#            return
#        if et == wx.wxEVT_COMMAND_FIND_REPLACE:
#            #self.mail_text_bundle.CallFunction(r[0], "Remove", r[0], r[1], in_context = True)
#            self.mail_text_bundle.CallFunction(r[0], "Replace", r[0] , r[1] ,self.replace_string, in_context = True)
#            self.search_buffer = self.mail_text_bundle.CurrentString()
#        elif et == wx.wxEVT_COMMAND_FIND_REPLACE_ALL:
#            while True:
#                self.mail_text_bundle.CallFunction(r[0], "Replace", r[0], r[1],self.replace_string, in_context = True)
#                self.search_buffer = self.mail_text_bundle.CurrentString()
#                self.GetFindFlags()
#                r = self.GetFindBuffer(suppress = True)
#                if not r:
#                    break
#        self.previous_flags = self.flags
#    def GetFindFlags(self):
#        """Get the find flags for replace/find dialog"""
#        if self.flags & 0x2 == 0:
#            if isinstance(self.find_string, basestring):
#                self.find_string = self.find_string.split()
#
#        if self.flags & 0x4 == 0:
#            self.search_buffer = self.search_buffer.lower()
#            if isinstance(self.find_string, list):
#                for i, value in enumerate(self.find_string):
#                    self.find_string[i] = self.find_string[i].lower()
#            else:
#                self.find_string = self.find_string.lower()
#
#        if self.previous_flags != self.flags:
#            self.IncrementIndex()
#
#    def GetFindBuffer(self, suppress = False):
#        """Return the current buffer outlining the current find selection"""
#        self.FindNext()
#        if self.search_index == -1:
#            if self.EndOfDocument(supress = suppress):
#                return None
#        if isinstance(self.find_string, list):
#            l = len(self.find_string[self.list_search_index])
#        else:
#            l = len(self.find_string)
#        r = (self.search_index, self.search_index + l)
#        self.mail_text_bundle.CallFunction(self.search_index, "ShowPosition", self.search_index, in_context = True)
#        self.mail_text_bundle.CallFunction(self.search_index, "SetSelection", self.search_index, self.search_index + l,  in_context = True)
#        self.mail_text_bundle.CallFunction(self.search_index, "ShowPosition", self.search_index, in_context = True)
#        self.IncrementIndex()
#        return r
#    
#    def FindNext(self):
#        """Find the next value in the search"""
#        if self.flags % 2 != 0:
#            if isinstance(self.find_string, list):
#                ret = []
#                for sub in self.find_string:
#                    temp = self.search_buffer.find(sub, self.search_index)
#                    if temp != -1:
#                        ret.append(temp)
#                if not len(ret):
#                    self.search_index = -1
#                else:
#                    self.search_index = min(ret)
#                    self.list_search_index = ret.index(self.search_index)
#            else:
#                self.search_index = self.search_buffer.find(self.find_string, self.search_index)
#        else:
#            if isinstance(self.find_string, list):
#                ret = []
#                for sub in self.find_string:
#                    temp = self.search_buffer.rfind(sub, 0, self.search_index)
#                    if temp != -1:
#                        ret.append(temp)
#                if not len(ret):
#                    self.search_index = -1
#                else:
#                    self.search_index = max(ret)
#                    self.list_search_index = ret.index(self.search_index)
#            else:
#                self.search_index = self.search_buffer.rfind(self.find_string, 0, self.search_index)
#    
#    def IncrementIndex(self):
#        """Increment the index of the search"""
#        if self.flags % 2 != 0:
#            self.search_index = self.search_index + 1
#        else:
#            self.search_index = self.search_index - 1
#      
#    def EndOfDocument(self, supress = False):
#        """Function handles the end of the document in a search"""
#        self.IncrementIndex()
#        self.FindNext()
#        if self.search_index == -1:
#            if not supress:
#                if isinstance(self.find_string, list):
#                    s = ' '.join(self.find_string)
#                    wx.MessageBox("Could not find string '%s' in the entire document." % s, "Error")
#                else:
#                    wx.MessageBox("Could not find string '%s' in the entire document." % self.find_string, "Error")
#            return True
#        else:
#            return False
